import _thread
import socket
import os
import threading
from time import time, sleep

from server.go import Go

go_clients = []
go_conn = []
rooms = []
audience_limit = 100
can_game_start = False
game = Go()
game_id = 0
notify_id = 0
who_to_go = "black"


class GoClient:
    identity_list = ["none", "player", "audience"]
    player_type_list = ["black", "white"]

    def __init__(self, c_id):
        self.id = c_id
        self.identity = GoClient.identity_list[0]
        self.player_type = None


def handle_request(c_id):
    global can_game_start, game, who_to_go, game_id
    lock = threading.Lock()
    client = None
    connection = None
    index = -1
    for i in range(len(go_clients)):
        if go_clients[i].id == c_id:
            client = go_clients[i]
            connection = go_conn[i]
            index = i

    select_role(client, connection)
    while not can_game_start:
        pass

    while True:
        data = connection.recv(1024)
        if str(data, "utf8").strip() == "exit":
            lock.acquire()
            go_clients.pop(index)
            go_conn.pop(index)
            lock.release()
            # 清空棋盘
            if client.identity == GoClient.identity_list[1]:
                if can_game_start:
                    game = Go()
                    who_to_go = GoClient.player_type_list[0]
                    game_id += 1
                    lock.acquire()
                    can_game_start = False
                    lock.release()
                    # 告知每一个客户端
                    for i in range(len(go_conn)):
                        if go_clients[i].identity != GoClient.identity_list[0]:
                            go_conn[i].send(bytes("game over", encoding="utf8"))
            # 退出
            connection.shutdown(2)
            connection.close()

            # 线程终止
            exit(0)

        if can_game_start:
            commands = str(data, "utf8").strip().split()
            print(commands)
            print(who_to_go)
            if len(commands) == 2 and who_to_go == client.player_type:
                a = 1 if who_to_go == GoClient.player_type_list[0] else -1
                r=game.step(a, (int(commands[0]), int(commands[1])))
                if not r:
                    continue
                # 给所有客户端都发送一份
                drop_mention = GoClient.player_type_list[0] if who_to_go == GoClient.player_type_list[1] else \
                GoClient.player_type_list[1]
                notify_all(True, drop_mention=drop_mention)
                # 交换落子
                who_to_go = GoClient.player_type_list[0] if who_to_go == GoClient.player_type_list[1] else \
                GoClient.player_type_list[1]
        else:
            # 等待游戏开始
            pass


def notify_all(ignore=False, drop_mention=GoClient.player_type_list[0]):
    global notify_id, game_id, go_clients, go_conn
    if (not ignore and game_id == notify_id) or ignore:
        for i in range(len(go_clients)):
            if go_clients[i].identity != GoClient.identity_list[0]:
                go_conn[i].send(bytes(str(game), encoding="utf8"))
            if go_clients[i].player_type == drop_mention:
                go_conn[i].send(bytes("Please drop a go chess\n", encoding="utf8"))
        if not ignore:
            notify_id += 1


def judge_start():
    global can_game_start, go_clients
    lock = threading.Lock()
    while True:
        if len([x for x in go_clients if
                x.identity == GoClient.identity_list[1]]) == 2 and not can_game_start:
            # 检测到对局开始 通知所有人
            notify_all()
            lock.acquire()
            can_game_start = True
            lock.release()


def select_role(client, connection):
    lock = threading.Lock()
    while True:
        connection.send(
            bytes("Please select a role,A for audience,B for black player,W for white player", encoding="utf8"))
        res = str(connection.recv(1024), "utf8")
        while filter(res):
            res = str(connection.recv(1024), "utf8")
        if res.strip() == "A":
            audience_num = len([x for x in go_clients if x.identity == GoClient.identity_list[2]])

            if audience_num < audience_limit:
                lock.acquire()
                client.identity = GoClient.identity_list[2]
                connection.send(bytes("choose to be audience", encoding="utf8"))
                lock.release()
                return
            else:
                connection.send(bytes("cannot choose to be an audience", encoding="utf8"))
        elif res.strip() == "B":
            player_num = len([x for x in go_clients if
                              x.identity == GoClient.identity_list[1] and x.player_type == GoClient.player_type_list[
                                  0]])
            if player_num == 0:
                lock.acquire()
                client.identity = GoClient.identity_list[1]
                client.player_type = GoClient.player_type_list[0]
                lock.release()
                connection.send(bytes("choose to be black player", encoding="utf8"))
                return
            else:
                connection.send(bytes("black player exists", encoding="utf8"))
        elif res.strip() == "W":
            player_num = len([x for x in go_clients if
                              x.identity == GoClient.identity_list[1] and x.player_type == GoClient.player_type_list[
                                  1]])
            if player_num == 0:
                lock.acquire()
                client.identity = GoClient.identity_list[1]
                client.player_type = GoClient.player_type_list[1]
                lock.release()
                connection.send(bytes("choose to be white player", encoding="utf8"))
                return
            else:
                connection.send(bytes("white player exists", encoding="utf8"))


def filter(msg):
    # 判断哪些是系统自动发的 哪些是用户手动输入的
    return msg == "heartbeat"


if __name__ == '__main__':
    _thread.start_new_thread(judge_start, ())
    while True:
        host = '127.0.0.1'
        port = 9999
        sk = socket.socket()
        sk.bind((host, port))
        sk.listen(5)
        print('The port is listening...')
        conn, address = sk.accept()
        print('Connect from: ', address)
        # 新建一个client对象
        client_id = int(time())
        go_clients.append(GoClient(client_id))
        go_conn.append(conn)
        try:
            _thread.start_new_thread(handle_request, (client_id,))
        except:
            print("无法启动线程")
            conn.close()
        sleep(1)
